<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>DNS Resolver Pro</title>
  <link rel="icon" href="https://rockblack.pro/images/favicon.ico" type="image/x-icon">
<style>
    body {
      font-family: 'Helvetica Neue', 'Segoe UI', Arial, sans-serif;
      margin: 0 auto;
      padding: 30px;
      max-width: 800px;
      background: #0f0f0f;
      color: #fff;
      line-height: 1.6;
    }
    body.light-mode {
      background: #f8f9fa;
      color: #333;
    }
    h2 {
      text-align: center;
      font-size: 2.2em;
      margin-bottom: 30px;
      color: #4CAF50;
    }
    .input-group {
      margin: 20px 0;
    }
    textarea {
      width: 100%;
      height: 150px;
      padding: 15px;
      border-radius: 8px;
      border: 2px solid #2d2d2d;
      background: #1a1a1a;
      color: #fff;
      font-family: 'Courier New', monospace;
    }
    body.light-mode textarea {
      background: #fff;
      border-color: #ddd;
      color: #333;
    }
    .controls {
      display: flex;
      gap: 15px;
      flex-wrap: wrap;
      margin: 25px 0;
      justify-content: center;
    }
    select, button {
      padding: 12px 20px;
      border-radius: 8px;
      border: none;
      font-weight: 600;
      cursor: pointer;
    }
    select {
      background: #1a1a1a;
      color: #fff;
      border: 2px solid #4CAF50;
    }
    body.light-mode select {
      background: #fff;
      border-color: #2196F3;
      color: #333;
    }
    button {
      background: linear-gradient(135deg, #4CAF50, #45a049);
      color: white;
    }
    .theme-toggle {
      background: linear-gradient(135deg, #673AB7, #512DA8);
    }
    pre {
      background: #1a1a1a;
      padding: 20px;
      border-radius: 8px;
      white-space: pre-wrap;
      border: 2px solid #2d2d2d;
      font-family: 'Courier New', monospace;
    }
    body.light-mode pre {
      background: #fff;
      border-color: #ddd;
    }
    .progress-container {
      width: 100%;
      height: 20px;
      background-color: #1a1a1a;
      border-radius: 10px;
      margin: 20px 0;
      overflow: hidden;
      display: none;
    }
    .progress-bar {
      height: 100%;
      background: linear-gradient(90deg, #4CAF50, #45a049);
      width: 0%;
      transition: width 0.3s ease;
      text-align: center;
      color: white;
      font-size: 12px;
      line-height: 20px;
    }
    body.light-mode .progress-container {
      background-color: #eee;
    }
    body.light-mode .progress-bar {
      background: linear-gradient(90deg, #2196F3, #1976D2);
    }
  </style>
</head>
<body>
  <h2>🔍 DNS Resolver Pro</h2>
  
  <div class="input-group">
    <textarea id="domains" placeholder="Введите домены каждый с новой строки"></textarea>
  </div>

  <div class="progress-container">
    <div class="progress-bar" id="progressBar">0%</div>
  </div>

  <div class="controls">
    <select id="format">
      <option value="standard">IPv4</option>
      <option value="keenetic">Keenetic</option>
      <option value="keenetic_clear">Keenetic route</option>
      <option value="keenetic_ip_min">Keenetic route Min</option>
    </select>
    <button onclick="resolveDomains()">🚀 Найти IP</button>
    <button onclick="saveToTxt()">💾 Сохранить в TXT</button>
    <button class="theme-toggle" onclick="toggleTheme()">🌓 Сменить тему</button>
  </div>

  <pre id="result">Результаты появятся здесь...</pre>

  <script>
    function normalizeDomain(input) {
      // Обработка URL (https://example.com)
      if (input.includes('://')) {
        try {
          const url = new URL(input);
          return url.hostname;
        } catch (e) {
          return input;
        }
      }
      
      // Обработка формата: 0: "example.com"
      const matchIndex = input.match(/^\s*\d+\s*:\s*"([^"]+)"\s*$/);
      if (matchIndex && matchIndex[1]) {
        return matchIndex[1];
      }
      
      // Обработка формата: "example.com",
      const matchQuotes = input.match(/^\s*"([^"]+)"\s*,?\s*$/);
      if (matchQuotes && matchQuotes[1]) {
        return matchQuotes[1];
      }
      
      return input.trim();
    }

    async function fetchDNSFromResolver(resolverName, url) {
      try {
        const options = (resolverName === 'Cloudflare') 
          ? { headers: { "accept": "application/dns-json" } }
          : {};
        const response = await fetch(url, options);
        const data = await response.json();
        return { resolver: resolverName, data };
      } catch (error) {
        return { resolver: resolverName, error: error.message };
      }
    }

    async function resolveDomainWithResolvers(domain) {
      const resolvers = [
        { name: "Google", url: `https://dns.google/resolve?name=${domain}&type=A` },
        { name: "Cloudflare", url: `https://cloudflare-dns.com/dns-query?name=${domain}&type=A` }
      ];
      const promises = resolvers.map(r => fetchDNSFromResolver(r.name, r.url));
      return await Promise.all(promises);
    }

    async function resolveDomains() {
      const domainsText = document.getElementById("domains").value;
      const rawLines = domainsText.split('\n').filter(line => line.trim() !== "");
      const domains = rawLines.map(normalizeDomain).filter(domain => domain !== "");
      const format = document.getElementById("format").value;
      const progressContainer = document.querySelector('.progress-container');
      const progressBar = document.getElementById('progressBar');
      
      progressContainer.style.display = 'block';
      progressBar.style.width = '0%';
      progressBar.textContent = '0%';
      
      let output = "";
      
      if (domains.length === 0) {
        document.getElementById("result").textContent = "Пожалуйста, введите хотя бы один домен.";
        progressContainer.style.display = 'none';
        return;
      }

      const totalDomains = domains.length;
      let processed = 0;

      const updateProgress = () => {
        const percent = Math.round((processed / totalDomains) * 100);
        progressBar.style.width = `${percent}%`;
        progressBar.textContent = `${percent}%`;
        
        if (percent === 100) {
          setTimeout(() => {
            progressContainer.style.display = 'none';
          }, 500);
        }
      };

      if (format === "keenetic_clear") {
        const uniqueIPs = new Set();
        for (let domain of domains) {
          try {
            const results = await resolveDomainWithResolvers(domain);
            results.forEach(result => {
              if (result.data?.Answer) {
                result.data.Answer
                  .filter(ans => ans.type === 1)
                  .forEach(ans => uniqueIPs.add(ans.data));
              }
            });
          } catch (error) {}
          processed++;
          updateProgress();
        }
        output = Array.from(uniqueIPs)
          .map(ip => `route add ${ip} mask 255.255.255.255 0.0.0.0`)
          .join('\n');
      } else if (format === "keenetic_ip_min") {
        const uniqueIPs = new Set();
        for (let domain of domains) {
          try {
            const results = await resolveDomainWithResolvers(domain);
            results.forEach(result => {
              if (result.data?.Answer) {
                result.data.Answer
                  .filter(ans => ans.type === 1)
                  .forEach(ans => uniqueIPs.add(ans.data));
              }
            });
          } catch (error) {}
          processed++;
          updateProgress();
        }
        
        // Группировка IP в подсети /24
        const cidrMap = new Map();
        uniqueIPs.forEach(ip => {
          if (ip === "0.0.0.0" || ip === "255.255.255.255") return;
          const octets = ip.split('.').map(Number);
          const network = `${octets[0]}.${octets[1]}.${octets[2]}.0/24`;
          cidrMap.set(network, true);
        });

        // Сортировка подсетей
        const sortedCidrs = Array.from(cidrMap.keys()).sort((a, b) => {
          const aParts = a.split('.').map(Number);
          const bParts = b.split('.').map(Number);
          for (let i = 0; i < 3; i++) {
            if (aParts[i] !== bParts[i]) {
              return aParts[i] - bParts[i];
            }
          }
          return 0;
        });

        output = sortedCidrs
          .map(cidr => `route add ${cidr.split('/')[0]} mask 255.255.255.0 0.0.0.0`)
          .join('\n');
      } else {
        for (let domain of domains) {
          output += `Домен: ${domain}\n`;
          try {
            const results = await resolveDomainWithResolvers(domain);
            results.forEach(result => {
              output += `  [${result.resolver}]\n`;
              if (result.error) {
                output += `    Ошибка: ${result.error}\n`;
              } else if (result.data?.Answer) {
                const aRecords = result.data.Answer.filter(ans => ans.type === 1);
                if (aRecords.length > 0) {
                  aRecords.forEach(ans => {
                    const ip = ans.data;
                    if (format === "keenetic") {
                      output += `    route add ${ip} mask 255.255.255.255 0.0.0.0\n`;
                    } else {
                      output += `    ${ip}\n`;
                    }
                  });
                } else {
                  output += `    Нет A записей.\n`;
                }
              } else {
                output += `    Нет ответа.\n`;
              }
            });
          } catch (error) {
            output += `  Ошибка: ${error.message}\n`;
          }
          processed++;
          updateProgress();
          output += "\n";
        }
      }
      
      document.getElementById("result").textContent = output.trim() || "Не удалось получить IP-адреса.";
      updateProgress();
    }

    function toggleTheme() {
      document.body.classList.toggle('light-mode');
    }
    
    function saveToTxt() {
  const content = document.getElementById("result").textContent;
  if (!content || content.trim() === "Результаты появятся здесь...") {
    alert("Нет данных для сохранения.");
    return;
  }
  const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = "dns_result.txt";
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}
    
  </script>
</body>
</html>
